﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;


namespace Nirvana
{
    /// <summary>
    /// Unity内置Shader检测规则脚本，检测Material，使用优化后的Shader替换内置标准shader。避免变体过大，占用ShaderLab内存过高。
    /// 注意：
    ///     规则文件必须存放在资源的父目录或同一级目录下。便于不同资源模块的管理。
    /// </summary>
    [CreateAssetMenu(fileName = "@BuildInShaderImportRule", menuName = "Nirvana/Asset/BuildInShaderImportRule")]
    public class BuildInShaderImportRule : ScriptableObject
    {
        /// <summary>
        /// 内置标准 Standerd shader
        /// </summary>
        [Tooltip("Replace Standerd Shader")]
        [SerializeField]
        private BoolVariate replace_Standerd;

        /// <summary>
        /// 内置标准 Particle Standard Surface shader
        /// </summary>
        [Tooltip("Replace Particle Standard Surface")]
        [SerializeField]
        private BoolVariate replace_ParticleStanderdSurface;

        [Tooltip("The asset check report.")]
        [SerializeField]
        [HideInInspector]
        private AssetCheckReport report;
        public AssetCheckReport Report { get { return report; } }

        /// <summary>
        ///         所有内置shader文件都放到shader目录
        /// </summary>
        [SerializeField]
        private string Default_Shader_Path = "Assets/Resources/BuildInShader/Shader";

        /// <summary>
        /// 返回当前配置脚本的存放目录
        /// </summary>
        /// <returns></returns>
        public string GetDirectorName()
        {
            string assetpath = AssetDatabase.GetAssetPath(this);
            return Path.GetDirectoryName(assetpath);
        }

        private void CheckMaterials(AssetCheckReport report, Material mat, string matpath)
        {
            if (this.replace_Standerd.IsHasValue() && mat.shader.name == "Standard")
            {
                string assetPath = AssetDatabase.GetAssetPath(mat.shader.GetInstanceID());
                if (!assetPath.StartsWith(Default_Shader_Path))
                {
                    report.assetpath = matpath;
                    report.objectname = mat.name;
                    report.hierarchyPath = null;
                    report.ShowWarnInfo("The material <b><color=orange>{0}</color></b> Use of <b><color=orange>Standerd</color></b> Shader!!", mat.name);
                }
            }

            if (this.replace_ParticleStanderdSurface.IsHasValue() && mat.shader.name == "Particles/Standard Surface")
            {
                string assetPath = AssetDatabase.GetAssetPath(mat.shader.GetInstanceID());
                if (!assetPath.StartsWith(Default_Shader_Path))
                {
                    report.assetpath = matpath;
                    report.objectname = mat.name;
                    report.hierarchyPath = null;
                    report.ShowWarnInfo("The material <b><color=orange>{0}</color></b> Use of <b><color=orange>Particles/Standard Surface</color></b> Shader!!", mat.name);
                }
            }
        }

        private void FindReplaceMaterials(AssetCheckReport report, Material mat, string matpath)
        {
            if (this.replace_Standerd.IsHasValue() && mat.shader.name == "StandardReplace")
            {
                string assetPath = AssetDatabase.GetAssetPath(mat.shader.GetInstanceID());
                if (assetPath.StartsWith(Default_Shader_Path))
                {
                    report.assetpath = matpath;
                    report.objectname = mat.name;
                    report.hierarchyPath = null;
                    report.ShowWarnInfo("The material <b><color=orange>{0}</color></b> Replace of <b><color=orange>Standerd</color></b> Shader!!", mat.name);
                }
            }

            if (this.replace_ParticleStanderdSurface.IsHasValue() && mat.shader.name == "Particles/Standard Surface")
            {
                string assetPath = AssetDatabase.GetAssetPath(mat.shader.GetInstanceID());
                if (assetPath.StartsWith(Default_Shader_Path))
                {
                    report.assetpath = matpath;
                    report.objectname = mat.name;
                    report.hierarchyPath = null;
                    report.ShowWarnInfo("The material <b><color=orange>{0}</color></b> Replace of <b><color=orange>Particles/Standard Surface</color></b> Shader!!", mat.name);
                }
            }
        }

        private void ReplaceMaterialShader(Material mat, string matpath)
        {
            if (this.replace_Standerd.IsHasValue() && this.replace_Standerd.GetValue() && mat.shader.name == "Standard")
            {
                string assetPath = AssetDatabase.GetAssetPath(mat.shader.GetInstanceID());
                if (!assetPath.StartsWith(Default_Shader_Path))
                {
                    string newShaderPath = Path.Combine(Default_Shader_Path, "StandardReplace.shader");
                    var shader = AssetDatabase.LoadAssetAtPath<Shader>(newShaderPath);
                    if (shader != null)
                        mat.shader = shader;
                    else
                    {
                        Debug.Log("The <b><color=orange>Standard</color></b> Shader isnot Exist !!");
                    }
                }
            }

            if (this.replace_ParticleStanderdSurface.IsHasValue() && this.replace_ParticleStanderdSurface.GetValue() && mat.shader.name == "Particles/Standard Surface")
            {
                string assetPath = AssetDatabase.GetAssetPath(mat.shader.GetInstanceID());
                if (!assetPath.StartsWith(Default_Shader_Path))
                {
                    string newShaderPath = Path.Combine(Default_Shader_Path, "Particle Standard Surface.shader");
                    var shader = AssetDatabase.LoadAssetAtPath<Shader>(newShaderPath);
                    if (shader != null)
                        mat.shader = shader;
                    else
                    {
                        Debug.Log("The <b><color=orange>Particles/Standard Surface</color></b> Shader isnot Exist !!");
                    }
                }
            }
        }
        public void FindMaterialsStandardShader()
        {
            if (this.report == null) this.report = new AssetCheckReport();
            else this.report.Clear();

            string findpath = GetDirectorName();
            string[] prefabGUIDArray = AssetDatabase.FindAssets("t:material", new string[] { findpath });
            for (int i = 0; i < prefabGUIDArray.Length; i++)
            {
                string path = AssetDatabase.GUIDToAssetPath(prefabGUIDArray[i]);
                var asset = AssetDatabase.LoadAssetAtPath<Material>(path);
                if (asset == null)
                {
                    continue;
                }

                var cancel = EditorUtility.DisplayCancelableProgressBar("FixMaterialsStandardShader", "Material -> " + asset.name, i * 1.0f / prefabGUIDArray.Length);
                if (cancel)
                {
                    break;
                }

                FindReplaceMaterials(report, asset, path);
            }
            EditorUtility.ClearProgressBar();

        }

        public void FixMaterialsStandardShader(bool isReplace)
        {
            if (this.report == null) this.report = new AssetCheckReport();
            else this.report.Clear();

            string findpath = GetDirectorName();
            string[] prefabGUIDArray = AssetDatabase.FindAssets("t:material", new string[] { findpath });
            for (int i = 0; i < prefabGUIDArray.Length; i++)
            {
                string path = AssetDatabase.GUIDToAssetPath(prefabGUIDArray[i]);
                var asset = AssetDatabase.LoadAssetAtPath<Material>(path);
                if (asset == null)
                {
                    continue;
                }

                var cancel = EditorUtility.DisplayCancelableProgressBar("FixMaterialsStandardShader", "Material -> " + asset.name, i * 1.0f / prefabGUIDArray.Length);
                if (cancel)
                {
                    break;
                }

                if (!isReplace) //只检测
                {
                    CheckMaterials(report, asset, path);
                }
                else
                {
                    ReplaceMaterialShader(asset, path);
                }

            }
            EditorUtility.ClearProgressBar();

        }


    }
}

